#include "GLI420Renderer.h"
#include "GLCommon.h"

namespace simple_renderer {

GLI420Renderer::GLI420Renderer(){

}

GLI420Renderer::~GLI420Renderer(){

}

const char *GLI420Renderer::GetFragmentShader(){
    return GLES2_getFragmentShader_yuv420p();
}

int GLI420Renderer::InitExtend(){
    //init i420 fragment shader
    us2_sampler[0] = glGetUniformLocation(program, "us2_SamplerX"); GLES2_checkError("glGetUniformLocation(us2_SamplerX)");
    us2_sampler[1] = glGetUniformLocation(program, "us2_SamplerY"); GLES2_checkError("glGetUniformLocation(us2_SamplerY)");
    us2_sampler[2] = glGetUniformLocation(program, "us2_SamplerZ"); GLES2_checkError("glGetUniformLocation(us2_SamplerZ)");

    um3_color_conversion = glGetUniformLocation(program, "um3_ColorConversion"); GLES2_checkError("glGetUniformLocation(um3_ColorConversion)");

    LOGI("[GLI420Renderer] InitExtend ok");

    return 0;
}

int GLI420Renderer::UseProgram(){

    //CPU -> GPU UNPACK
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glUseProgram(program);            GLES2_checkError("glUseProgram");
    if(plane_textures[0] == 0)
        glGenTextures(3, plane_textures);

    for(int i=0; i<3; i++){

        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, plane_textures[i]);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glUniform1i(us2_sampler[i], i);
    }

    glUniformMatrix3fv(um3_color_conversion, 1, GL_FALSE, GLES2_getColorMatrix_bt709());

    return 0;
}

int GLI420Renderer::UploadTexture(const PicFrame &pic_frame){

    int     planes[3]    = { 0, 1, 2 };
    uint16_t *pitches = pic_frame.GetPitches();
    if(pitches == nullptr){
        LOGE("[GLI420Renderer] UploadTexture pitches=%p", pitches);
        return -1;
    }
    uint8_t **pixs = pic_frame.GetPixels();
    if(pixs == nullptr){
        LOGE("[GLI420Renderer] UploadTexture pixs=%p", pixs);
        return -1;
    }
    int h = pic_frame.GetHeight();

    const GLsizei widths[3]    = { pitches[0], pitches[1], pitches[2] };
    const GLsizei heights[3]   = { h,          h / 2,      h / 2 };
    const GLubyte *pixels[3]   = { pixs[0],  pixs[1],  pixs[2] };

    //LOGV("[GLI420Renderer] widths[0]=%d widths[1]=%d widths[2]=%d ", widths[0], widths[1], widths[2]);
    //LOGV("[GLI420Renderer] heights[0]=%d heights[1]=%d heights[2]=%d ", heights[0], heights[1], heights[2]);
    //LOGV("[GLI420Renderer] pixels[0]=%p pixels[1]=%p pixels[2]=%p ", pixels[0], pixels[1], pixels[2]);

    if(pic_frame.GetFrameType() == kYV12){
        planes[1] = 2;
        planes[2] = 1;
    }

    for(int i=0; i<3; i++){
        int plane = planes[i];
        glBindTexture(GL_TEXTURE_2D, plane_textures[i]);
        glTexImage2D(GL_TEXTURE_2D,
                     0,
                     GL_LUMINANCE,   /** yuv there is luminance */
                     widths[plane],
                     heights[plane],
                     0,
                     GL_LUMINANCE,
                     GL_UNSIGNED_BYTE,
                     pixels[plane]);
        //LOGI("[GLI420Renderer] UploadTexture plane=%d", plane);
    }

    //LOGI("[GLI420Renderer] UploadTexture ok");
    return 0;
}

}